package algo3.g203.vista;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import algo3.g203.modelo.armas.Arma;
import algo3.g203.modelo.armas.ArmaConvencional;
import algo3.g203.modelo.armas.MinaDobleConRetardo;
import algo3.g203.modelo.armas.MinaPorContacto;
import algo3.g203.modelo.armas.MinaPuntualConRetardo;
import algo3.g203.modelo.armas.MinaTripleConRetardo;
import algo3.g203.modelo.fisica.DireccionDerecha;
import algo3.g203.modelo.fisica.DireccionInferiorDerecha;
import algo3.g203.modelo.fisica.DireccionIzquierda;
import algo3.g203.modelo.fisica.DireccionSuperior;
import algo3.g203.modelo.fisica.DireccionSuperiorDerecha;
import algo3.g203.modelo.fisica.Posicion;
import algo3.g203.modelo.juego.Juego;
import algo3.g203.modelo.juego.Jugador;
import algo3.g203.modelo.juego.ObservadorDeJuego;
import algo3.g203.modelo.naves.Buque;
import algo3.g203.modelo.naves.Destructor;
import algo3.g203.modelo.naves.Lancha;
import algo3.g203.modelo.naves.Nave;
import algo3.g203.modelo.naves.Portaaviones;
import algo3.g203.modelo.naves.Rompehielos;
import algo3.g203.modelo.tablero.ObservadorDeTablero;
import algo3.g203.modelo.tablero.Tablero;
import algo3.g203.vista.armas.VistaArma;
import algo3.g203.vista.armas.VistaArmaConvencional;
import algo3.g203.vista.armas.VistaMinaDobleConRetardo;
import algo3.g203.vista.armas.VistaMinaPorContacto;
import algo3.g203.vista.armas.VistaMinaPuntualConRetardo;
import algo3.g203.vista.armas.VistaMinaTripleConRetardo;
import algo3.g203.vista.naves.VistaBuque;
import algo3.g203.vista.naves.VistaDestructor;
import algo3.g203.vista.naves.VistaLancha;
import algo3.g203.vista.naves.VistaNave;
import algo3.g203.vista.naves.VistaPortaaviones;
import algo3.g203.vista.naves.VistaRompehielos;

import fiuba.algo3.titiritero.modelo.*;
import fiuba.algo3.titiritero.dibujables.*;

import javax.swing.*;
public class VentanaPrincipal {

	private JFrame frame;
	private GameLoop gameLoop;
	
	private Tablero tablero;
	private JLabel puntaje;
	private Jugador jugador = new Jugador();
	private Juego juego;
	private JTextField posX,posY;
	private JPanel panel;
	
	private List<ObjetoDibujable> listaDibujables;
	private List<ObjetoPosicionable> listaPosicionables;
	
	/**
	 * Iniciar aplicacion.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					VentanaPrincipal window = new VentanaPrincipal();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public VentanaPrincipal() {
		try {
			initialize();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Initialize the contents of the frame.
	 * @throws IOException 
	 */
	private void initialize() throws IOException {
		this.listaDibujables = new ArrayList<ObjetoDibujable>();
		this.listaPosicionables = new ArrayList<ObjetoPosicionable>();
		
		frame = new JFrame();
		
		frame.setForeground(new Color(0, 0, 0));
		
		frame.setBounds(50, 50, 825, 650);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);
		frame.setTitle("BATALLA NAVALGO");
		
		JButton btnIniciar = this.addBotonIniciar();
		JButton btnComenzarTurno = this.addBotonComenzarTurno();
		
		this.posX = this.addPosicionX();
        this.posY = this.addPosicionY();
        
		this.addIndicadorPosX();
		this.addIndicadorPosY();
		this.addBotonArmaConvencional();
		this.addBotonMinaContacto();
		this.addBotonMinaPuntual();
		this.addBotonMinaDoble();
		this.addBotonMinaTriple();
		
		this.panel = this.addSuperficiePanel(); 
		
		this.gameLoop = new GameLoop((SuperficieDeDibujo) panel);
		
		this.inicializarModelo();
		
		this.puntaje = this.addPuntaje();
		
		this.addMouseListener(panel);

		this.addKeyListener();

		this.setComponentsFocus(btnIniciar, btnComenzarTurno);
		
	}

	private void inicializarModelo() throws IOException {

		// Creacion de naves del modelo
		Lancha lancha1 = new Lancha(new Posicion(4,2),new DireccionDerecha());
		Lancha lancha2 = new Lancha(new Posicion(3,2),new DireccionSuperiorDerecha());
		Destructor destructor1 = new Destructor(new Posicion(5,0),new DireccionIzquierda());
		Destructor destructor2 = new Destructor(new Posicion(9,4),new DireccionSuperior());
		Portaaviones portaaviones1 = new Portaaviones(new Posicion(6,5),new DireccionSuperior());
		Rompehielos rompehielos1 = new Rompehielos(new Posicion(3,7),new DireccionSuperiorDerecha());
		Buque buque1 = new Buque(new Posicion(6,6),new DireccionInferiorDerecha());
		
		// Inicializacion del modelo
		tablero = new Tablero();
		tablero.agregarObservador(new ObservadorDeTableroConcreto());
		
		tablero.colocarNave(lancha1);
		tablero.colocarNave(lancha2);
		tablero.colocarNave(destructor1);
		tablero.colocarNave(destructor2);
		tablero.colocarNave(portaaviones1);
		tablero.colocarNave(rompehielos1);
		tablero.colocarNave(buque1);
		
		
		juego = new Juego(tablero,jugador);		
		juego.agregarObservador(new ObservadorDeJuegoConcreto());
		
		// Carga de naves al framework
		this.agregarLancha(lancha1);		
		this.agregarLancha(lancha2);
		this.agregarDestructor(destructor1);
		this.agregarDestructor(destructor2);
		this.agregarPortaaviones(portaaviones1);
		this.agregarRompehielos(rompehielos1);
		this.agregarBuque(buque1);
	
		
	}
	
	private void agregarLancha(Lancha lancha) throws IOException {
		VistaNave vNaveLancha = new VistaLancha(lancha);
		this.gameLoop.agregar(lancha);
		this.gameLoop.agregar(vNaveLancha);
		
		this.listaPosicionables.add(lancha);
		this.listaDibujables.add(vNaveLancha);
	}
	
	
	private void agregarDestructor(Destructor destructor) throws IOException {
		VistaNave vNaveDestructor = new VistaDestructor(destructor);
		this.gameLoop.agregar(destructor);
		this.gameLoop.agregar(vNaveDestructor);
		
		this.listaPosicionables.add(destructor);
		this.listaDibujables.add(vNaveDestructor);
	}
	
	private void agregarPortaaviones(Portaaviones portaaviones) throws IOException {
		VistaNave vNavePortaaviones = new VistaPortaaviones(portaaviones);
		this.gameLoop.agregar(portaaviones);
		this.gameLoop.agregar(vNavePortaaviones);
		
		this.listaPosicionables.add(portaaviones);
		this.listaDibujables.add(vNavePortaaviones);
	}
	
	private void agregarRompehielos(Rompehielos rompehielos) throws IOException {
		VistaNave vNaveRompehielos = new VistaRompehielos(rompehielos);
		this.gameLoop.agregar(rompehielos);
		this.gameLoop.agregar(vNaveRompehielos);
		
		this.listaPosicionables.add(rompehielos);
		this.listaDibujables.add(vNaveRompehielos);
	}
	
	private void agregarBuque(Buque buque) throws IOException {
		VistaNave vNaveBuque = new VistaBuque(buque);
		this.gameLoop.agregar(buque);
		this.gameLoop.agregar(vNaveBuque);
		
		this.listaPosicionables.add(buque);
		this.listaDibujables.add(vNaveBuque);
	}


	private void setComponentsFocus(JButton btnIniciar, JButton btnDetener) {
		frame.setFocusable(true);
		btnDetener.setFocusable(false);
		btnIniciar.setFocusable(false);
	}

	private void addKeyListener() {
		frame.addKeyListener(new KeyListener(
				) {
			
			@Override
			public void keyTyped(KeyEvent arg0) {
				System.out.println("Key pressed");
			}
			
			@Override
			public void keyReleased(KeyEvent arg0) {
			}
			
			@Override
			public void keyPressed(KeyEvent arg0) {
				System.out.println("Ping");
			}  
			 	
		});
	}

	private void addMouseListener(JPanel panel) {
		panel.addMouseListener(new MouseAdapter() {
					
			@Override
			public void mouseClicked(MouseEvent arg0) {		
				posX.setText(Integer.toString(arg0.getX()/50));
				posY.setText(Integer.toString(arg0.getY()/50));
			}});
	}

	private JPanel addSuperficiePanel() {
		JPanel panel = new SuperficiePanel();
		panel.setBackground(Color.CYAN);
		panel.setBounds(275, 75, 500, 500);
		frame.getContentPane().add(panel);
		return panel;
	}
	
	private JLabel addPuntaje(){
		JLabel puntaje = new JLabel("PUNTOS: "+Integer.toString(juego.getPuntaje()));

		puntaje.setBounds(10, 0, 200, 100);
		
		frame.getContentPane().add(puntaje);
		return puntaje;
		
	}
	
	private JLabel addIndicadorPosX(){
		JLabel posX = new JLabel("POSICION EN X:");
		posX.setBounds(10, 310,220,30);
		frame.getContentPane().add(posX);
		
		return posX;
	}
	
	private JTextField addPosicionX(){
		JTextField posX = new JTextField("0");
		posX.setBounds(120, 310, 100, 30);
		frame.getContentPane().add(posX);
		return posX;
		
	}
	
	private JTextField addPosicionY(){
		JTextField posY = new JTextField("0");
		posY.setBounds(120, 350, 100, 30);
		frame.getContentPane().add(posY);
		return posY;
		
	}
	
	private JLabel addIndicadorPosY(){
		JLabel posY = new JLabel("POSICION EN Y:");
		posY.setBounds(10,350,220, 30);
		frame.getContentPane().add(posY);
		return posY;
		
	}
	
	private JButton addBotonIniciar() {
		JButton btnIniciar = new JButton("Iniciar");
		btnIniciar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				gameLoop.setFrecuencia(200);
				gameLoop.iniciarEjecucion();
			}
		});
		btnIniciar.setBounds(300, 16, 77, 25);
		frame.getContentPane().add(btnIniciar);
		
		return btnIniciar;
	}
	
	private JButton addBotonComenzarTurno() {
		JButton btnDetener = new JButton("Pasar Turno");
		btnDetener.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				juego.comenzarTurno();
				actualizarPuntaje();
			}
		});
		btnDetener.setBounds(500, 16, 150, 25);
		frame.getContentPane().add(btnDetener);
		return btnDetener;
	}
	
	private Posicion leerFieldsPosicion() {
	
		int x = Integer.parseInt(posX.getText());
		int y = Integer.parseInt(posY.getText());
			
		return new Posicion(x, y);

	}
	
	private void actualizarPuntaje() {
        this.puntaje.setText("PUNTOS: " + Integer.toString(juego.getPuntaje()));
	}
	
	private JButton addBotonArmaConvencional(){
		JButton botonArmaConvencional = new JButton("Arma Convencional (200)");
		botonArmaConvencional.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0){
				Arma arma = new ArmaConvencional(leerFieldsPosicion());
				VistaArma vArma = new VistaArmaConvencional(arma);
				
				if (juego.colocarArma(arma)) {
					actualizarPuntaje();
						
					// Agrego al framework
					gameLoop.agregar(arma);
					gameLoop.agregar(vArma);
					
					System.out.println("ArmaConvencional creada - Puntaje jugador: " + juego.getPuntaje());
					
					// Agrego a mi lista
					listaPosicionables.add(arma);
					listaDibujables.add(vArma);
				}
			}
		});
		
		botonArmaConvencional.setBounds(10,70,220,30);
		frame.getContentPane().add(botonArmaConvencional);
		return botonArmaConvencional;
	}
	
	private JButton addBotonMinaContacto(){
		JButton botonMinaContacto = new JButton("Mina Por Contacto (150)");
		botonMinaContacto.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0){
				Arma arma = new MinaPorContacto(leerFieldsPosicion(), tablero);
				VistaArma vArma = new VistaMinaPorContacto(arma);

				if (juego.colocarArma(arma)) {
					actualizarPuntaje();
					
					// Agrego al framework
					gameLoop.agregar(arma);
					gameLoop.agregar(vArma);
					
					System.out.println("MinaPorContacto creada - Puntaje jugador: " + juego.getPuntaje());
					
					// Agrego a mi lista
					listaPosicionables.add(arma);
					listaDibujables.add(vArma);
				}
			}
		});
		
		botonMinaContacto.setBounds(10,110,220,30);
		frame.getContentPane().add(botonMinaContacto);
		return botonMinaContacto;
	}
	
	private JButton addBotonMinaPuntual(){
		JButton botonMinaPuntual = new JButton("Mina Puntual Con Retardo (50)");
		botonMinaPuntual.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0){
				Arma arma = new MinaPuntualConRetardo(leerFieldsPosicion());
				VistaArma vArma = new VistaMinaPuntualConRetardo(arma);
				
				if (juego.colocarArma(arma)) {
					actualizarPuntaje();
						
					// Agrego al framework
					gameLoop.agregar(arma);
					gameLoop.agregar(vArma);
					
					System.out.println("Mina Puntal creada - Puntaje jugador: " + juego.getPuntaje());
					
					// Agrego a mi lista
					listaPosicionables.add(arma);
					listaDibujables.add(vArma);
				}
				
			}
		});
		botonMinaPuntual.setBounds(10,150,220,30);
		frame.getContentPane().add(botonMinaPuntual);
		return botonMinaPuntual;
	}
	
	private JButton addBotonMinaDoble(){
		JButton botonMinaDoble = new JButton("Mina Doble Con Retardo (100)");
		botonMinaDoble.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0){
				Arma arma = new MinaDobleConRetardo(leerFieldsPosicion());
				VistaArma vArma = new VistaMinaDobleConRetardo(arma);
				
				if (juego.colocarArma(arma)) {
					actualizarPuntaje();
					
					// Agrego al framework
					gameLoop.agregar(arma);
					gameLoop.agregar(vArma);
					
					System.out.println("Mina Doble creada - Puntaje jugador: " + juego.getPuntaje());
					
					// Agrego a mi lista
					listaPosicionables.add(arma);
					listaDibujables.add(vArma);
				}
			}
		});
		
		botonMinaDoble.setBounds(10,190,220,30);
		frame.getContentPane().add(botonMinaDoble);
		return botonMinaDoble;
	}
	
	private JButton addBotonMinaTriple(){
		JButton botonMinaTriple = new JButton("Mina Triple Con Retardo (125)");
		botonMinaTriple.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0){
				Arma arma = new MinaTripleConRetardo(leerFieldsPosicion());
				VistaArma vArma = new VistaMinaTripleConRetardo(arma);
				
				if (juego.colocarArma(arma)) {
					actualizarPuntaje();
						
					// Agrego al framework
					gameLoop.agregar(arma);
					gameLoop.agregar(vArma);
					
					System.out.println("Mina Triple creada - Puntaje jugador: " + juego.getPuntaje());
					
					// Agrego a mi lista
					listaPosicionables.add(arma);
					listaDibujables.add(vArma);
				}
			}
		});
		
		botonMinaTriple.setBounds(10,230,220,30);
		frame.getContentPane().add(botonMinaTriple);
		return botonMinaTriple;
	}
	
	private class ObservadorDeTableroConcreto implements ObservadorDeTablero {

		@Override
		public void notificarNaveEliminada(Nave n) {
			gameLoop.remover(n);
			gameLoop.remover(listaDibujables.get(listaPosicionables.indexOf(n)));
			
			int pos = listaPosicionables.indexOf(n);
			listaPosicionables.remove(pos);
			listaDibujables.remove(pos);
		}

		@Override
		public void notificarArmaEliminada(Arma a) {

			/*
			 * Quitar las armas ya explotadas luego de ser notificados no da tiempo al titiritero
			 * para mostrar la explosion. Asi que no quitamos las armas. En vez de eso, luego de
			 * explotar las minas siguen en el titiritero pero no se dibujan.  
			 */
			
		}

	}
	
	private class ObservadorDeJuegoConcreto implements ObservadorDeJuego {

		@Override
		public void notificarJuegoGanado() {
			JOptionPane.showMessageDialog(frame,
					"JUEGO GANADO!! \n" + puntaje.getText(),
					"BatallaNavago!",
					JOptionPane.INFORMATION_MESSAGE);
			System.exit(0);
		}

		@Override
		public void notificarJuegoPerdido() {
			JOptionPane.showMessageDialog(frame,
					"JUEGO PERDIDO\nTE QUEDASTE SIN PUNTOS!! \n",
					"BatallaNavalgo!",
					JOptionPane.INFORMATION_MESSAGE);
			System.exit(0);
		}
		
	}
	
}
